﻿namespace ContactsSync.Providers.Google2
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration;
    using System.Drawing;
    using System.IO;
    using System.Net;
    using System.Reflection;
    using System.Text;
    using ContactsSync.Infrastructure.Models;
    using Google.GData.Contacts;
    using Microsoft.Practices.Composite.Events;

    public class GoogleContactsProvider : IContactsProvider
    {
        private readonly string username;
        private readonly string password;
        private string authToken;

        public GoogleContactsProvider()
        {
            string path = Path.Combine("Modules", Assembly.GetExecutingAssembly().ManifestModule.Name);
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(path);

            this.username = configuration.AppSettings.Settings["user"].Value;
            this.password = configuration.AppSettings.Settings["password"].Value;
        }

        public event EventHandler<DataEventArgs<IList<ContactsSync.Infrastructure.Models.Contact>>> RetrieveContactsCompleted;

        public string ProviderName
        {
            get { return "Google"; }
        }

        public void RetrieveContactsAsync()
        {
            try
            {
                this.Login();

                ContactsService cs = new ContactsService("ContactsSync");
                cs.SetAuthenticationToken(this.authToken);

                BackgroundWorker backgroundWorker = new BackgroundWorker();
                backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);
                backgroundWorker.DoWork += new DoWorkEventHandler(this.BackgroundWorker_DoWork);
                backgroundWorker.RunWorkerAsync(cs);
            }
            catch
            {
                this.OnRetrieveContactsCompleted(new List<Contact>());
            }
        }

        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            ContactsService googleService = e.Argument as ContactsService;
            List<ContactsSync.Infrastructure.Models.Contact> contacts = new List<ContactsSync.Infrastructure.Models.Contact>();

            ContactsQuery query = new ContactsQuery(ContactsQuery.CreateContactsUri("default"));
            query.NumberToRetrieve = 500;

            ContactsFeed feed = googleService.Query(query);
            
            foreach (ContactEntry entry in feed.Entries)
            {
                ContactsSync.Infrastructure.Models.Contact contact = new ContactsSync.Infrastructure.Models.Contact
                            {
                                Id = entry.Id.ToString(),
                                FirstName = entry.Title.Text,
                                LastName = string.Empty,
                                ImageSource = this.RetrieveImage(entry),
                            };
                contacts.Add(contact);
            }

            contacts.Sort((c1, c2) => string.Compare(c1.FirstName, c2.FirstName, StringComparison.Ordinal));

            e.Result = contacts;
        }

        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            IList<ContactsSync.Infrastructure.Models.Contact> contacts = e.Result as IList<ContactsSync.Infrastructure.Models.Contact>;

            if (contacts == null)
            {
                contacts = new List<ContactsSync.Infrastructure.Models.Contact>();
            }

            this.OnRetrieveContactsCompleted(contacts);
        }

        private void OnRetrieveContactsCompleted(IList<ContactsSync.Infrastructure.Models.Contact> contacts)
        {
            EventHandler<DataEventArgs<IList<ContactsSync.Infrastructure.Models.Contact>>> completed = this.RetrieveContactsCompleted;
            if (completed != null)
            {
                completed(this, new DataEventArgs<IList<ContactsSync.Infrastructure.Models.Contact>>(contacts));
            }
        }

        private Image RetrieveImage(ContactEntry entry)
        {
            try
            {
                ASCIIEncoding encoding = new ASCIIEncoding();
                HttpWebRequest request;
                request = (HttpWebRequest)WebRequest.Create(entry.PhotoUri.ToString());
                request.Method = "GET";
                request.Headers.Add("Authorization", "GoogleLogin auth=" + this.authToken);

                request.ContentType = "image/*";

                HttpWebResponse myHttpWebResponse = (HttpWebResponse)request.GetResponse();

                Stream streamResponse = myHttpWebResponse.GetResponseStream();

                byte[] readBuffer = new byte[300000];

                int count = streamResponse.Read(readBuffer, 0, readBuffer.Length);

                MemoryStream stream = new MemoryStream(readBuffer);
                Image img = Bitmap.FromStream(stream);

                streamResponse.Close();

                myHttpWebResponse.Close();

                return img;
            }
            catch
            {
                return null;
            }
        }

        private void Login()
        {
            ASCIIEncoding encoding = new ASCIIEncoding();

            string postData = string.Format("accountType=HOSTED_OR_GOOGLE&Email={0}&Passwd={1}&service=cp&source=ContactsSync", this.username, this.password);

            byte[] buffer = encoding.GetBytes(postData);

            HttpWebRequest request;
            request = (HttpWebRequest)WebRequest.Create("https://www.google.com/accounts/ClientLogin");
            request.Method = "POST";

            // Set the content type to a FORM
            request.ContentType = "application/x-www-form-urlencoded";

            // Get length of content
            request.ContentLength = buffer.Length;

            // Get request stream
            Stream newStream = request.GetRequestStream();

            // Send the data.
            newStream.Write(buffer, 0, buffer.Length);

            // Close stream
            newStream.Close();

            // Assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable.
            HttpWebResponse myHttpWebResponse = (HttpWebResponse)request.GetResponse();

            // Display the contents of the page to the console.
            Stream streamResponse = myHttpWebResponse.GetResponseStream();

            // Get stream object
            StreamReader streamRead = new StreamReader(streamResponse);

            char[] readBuffer = new char[256];
            string resultDataTotal = string.Empty;

            // Read from buffer
            int count = streamRead.Read(readBuffer, 0, 256);

            while (count > 0)
            {
                // get string
                string resultData = new string(readBuffer, 0, count);

                // Write the data
                Console.WriteLine(resultData);
                resultDataTotal = resultDataTotal + resultData;

                // Read from buffer
                count = streamRead.Read(readBuffer, 0, 256);
            }

            // Release the response object resources.
            streamRead.Close();
            streamResponse.Close();

            // Close response
            myHttpWebResponse.Close();

            this.authToken = resultDataTotal.Substring(resultDataTotal.IndexOf("Auth=") + 5);
        }
    }
}
